package org.social.module;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections4.MapUtils;
import org.bean.ChatRoom;
import org.bean.SourceChatMsg;
import org.cfg.DiscreteDataCfg;
import org.cfg.cache.DiscreteDataCfgCache;
import org.constant.ChatConstant;
import org.constant.DiscreteDataID;
import org.constant.DiscreteDataKey;
import org.constant.FriendConstant;
import org.error.GameErrorCode;
import org.remote.game.RemoteGameServer;
import org.social.db.bean.Friend;
import org.social.db.bean.PlayerMap;
import org.social.db.cache.FriendCache;
import org.social.db.cache.PlayerMapCache;
import org.utils.RemoteUtil;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sojoys.artifact.exception.AbstractLogicModelException;
import com.sojoys.artifact.tools.ToolError;
import com.sojoys.artifact.tools.ToolMap;
import com.xiaoleilu.hutool.util.RandomUtil;

/**
 * @author : DengYing
 * @CreateDate : 2017年12月4日 上午10:13:52
 * @Description ：Please describe this document
 */
public class ChatManager {
	private ChatManager() {
	}

	private static ChatManager ME = new ChatManager();

	public static ChatManager me() {
		return ME;
	}
	
	// 聊天房间缓存
	private Map<Integer, ChatRoom> chatRoomCache = Maps.newConcurrentMap();
	
	// 玩家房间号映射
	private Map<Integer, Integer> playerRoomMaping = Maps.newConcurrentMap();
	
	/**
	 * 发送聊天
	 * @param msg
	 * @throws AbstractLogicModelException
	 */
	public void sendChat(SourceChatMsg msg) throws AbstractLogicModelException {
		// 需要通知的服务器
		Map<String, Set<Integer>> serverMaping = Maps.newHashMap();
		RemoteGameServer remoteGameServer = null;
		PlayerMap sourcePlayerMap = PlayerMapCache.me().getByPid(msg.getSourcePid());
		
		if (sourcePlayerMap!=null) {
			msg.setLvl(sourcePlayerMap.getPlayerMapProxy().getPlv());
			msg.setHelpFightHeroCid(sourcePlayerMap.getPlayerMapProxy().getHelpHeroCid());
		}
		
		switch (msg.getChannel()) {
		// 世界聊天
		case ChatConstant.CHANNEL_WORLD:
			ChatRoom chatRoom = getChatRoom(msg.getSourcePid(),msg.getChatRoomId());
			// 加入聊天缓存
			chatRoom.addMsg(msg);
			Set<Integer> pids = chatRoom.getPids();
			for (Integer pid : pids) {
				PlayerMap playerMap = PlayerMapCache.me().getByPid(pid);
				if (playerMap == null) {
					continue;
				}
				createChatPushTargets(serverMaping, playerMap);
			}
			break;
		// 私聊
		case ChatConstant.CHANNEL_PRIVATE:
			
			Friend shield = FriendCache.me().getByPlayerIdFriendIdStatus(msg.getTargetId(), msg.getSourcePid(), FriendConstant.STATUS_SHIELD);
			ToolError.isAndTrue(GameErrorCode.YOU_HAVE_BEEN_SHIELDED, "已被对方屏蔽", shield != null);
			
			ToolError.isAndTrue(GameErrorCode.PRIVATE_CHAT_NOT_FOND, "私聊对象不存在", sourcePlayerMap == null);
			createChatPushTargets(serverMaping, sourcePlayerMap);
			
			PlayerMap targetPlayerMap = PlayerMapCache.me().getByPid(msg.getTargetId());
			ToolError.isAndTrue(GameErrorCode.PRIVATE_CHAT_NOT_FOND, "私聊对象不存在", targetPlayerMap == null);
			createChatPushTargets(serverMaping, targetPlayerMap);
			break;
		// 公告
		case ChatConstant.CHANNEL_SYSTEM:
			// 系统木人发送全服、全部人
			remoteGameServer = RemoteUtil.gameTopic();
			remoteGameServer.notifyChat(msg, new HashSet<>(0));
			break;
		// 队伍
//		case ChatConstant.CHANNEL_TEAM:
//			AbstractTeam team = TeamManager.me().getTeamById(Long.valueOf(msg.getTargetId()));
//			ToolError.isAndTrue(GameErrorCode.NOT_FOND_TEAM, "队伍不存在", team == null);
//			team.getMembers().forEach((pid,menber)->{
//				PlayerMap playerMap = PlayerMapCache.me().getByPid(pid);
//				if (playerMap == null) {
//					return;
//				}
//				createChatPushTargets(serverMaping, playerMap);
//			});
//			break;
		default:
			ToolError.isAndTrue(GameErrorCode.NOT_FOND_CHAT_TYPE, "频道错误", true);
			break;
		}

		for (Entry<String, Set<Integer>> entry : serverMaping.entrySet()) {
			remoteGameServer = RemoteUtil.gameAsyn(entry.getKey());
			// 向游戏服转发聊天信息
			remoteGameServer.notifyChat(msg, entry.getValue());
		}
	}
	
	/** 创建推送目标 */
	private void createChatPushTargets(Map<String, Set<Integer>> serverMaping, PlayerMap playerMap) {
		Set<Integer> serverPids = serverMaping.get(playerMap.getServerId());
		if (serverPids == null) {
			serverPids = Sets.newHashSet();
			serverMaping.put(playerMap.getServerId(), serverPids);
		}
		serverPids.add(playerMap.getPid());
	}
	
	
	public ChatRoom getChatRoom(int pid,int oldRoomId){
		int roomId = MapUtils.getIntValue(playerRoomMaping, pid,oldRoomId);
		ChatRoom chatRoom = chatRoomCache.get(roomId);
		if (chatRoom == null && roomId > 0) {
			chatRoom = new ChatRoom(roomId);
			chatRoomCache.put(roomId, chatRoom);
			chatRoom.addPid(pid);
			playerRoomMaping.put(pid, roomId);
		}
		return chatRoom;
	}
	
	/**
	 * 进入聊天室
	 * @param pid
	 * @param exitRoomId
	 * @param assignRoomId
	 * @return
	 */
	public ChatRoom enterChatRoom(int pid,int exitRoomId,int assignRoomId){
		ChatRoom room = null;
		if (assignRoomId > 0) {
			// 指定房间
			room = chatRoomCache.get(assignRoomId);
			if (room==null) {
				room = new ChatRoom(assignRoomId);
				chatRoomCache.put(assignRoomId, room);
			}
		}else {
			// 随机房间
			
			int defaultRoomId = 1; // 默认房间ID
			DiscreteDataCfg cfg = DiscreteDataCfgCache.me().getById(DiscreteDataID.CHAT_ROOM_LIMIT);
			// 房间最大容量
			int roomLimit = ToolMap.getInt(DiscreteDataKey.MAX, cfg.getData(),100);
			
			// 符合条件的房间
			List<ChatRoom> conformRooms = new ArrayList<>(3);
			
			if (chatRoomCache.isEmpty()) {
				ChatRoom newRoom = new ChatRoom(defaultRoomId);
				chatRoomCache.put(defaultRoomId, newRoom);
				conformRooms.add(newRoom);
			}else {
				// 查找一个未装满的房间
				for (Entry<Integer, ChatRoom> entry : chatRoomCache.entrySet()) {
					defaultRoomId = Math.max(defaultRoomId, entry.getKey());
					// 本来的房间
					if (exitRoomId == entry.getKey()) {
						continue;
					}
					ChatRoom chatRoom = entry.getValue();
					if (chatRoom.getPids().size() < roomLimit) {
						conformRooms.add(chatRoom);
					}
				}
				
				// 所有房间已满，分配新的房间
				if (conformRooms.isEmpty()) {
					defaultRoomId++;
					ChatRoom newRoom = new ChatRoom(defaultRoomId);
					chatRoomCache.put(defaultRoomId, newRoom);
					conformRooms.add(newRoom);
				}
			}
			// 随机一个房间
			room = RandomUtil.randomEle(conformRooms);
		}
		
		room.addPid(pid);
		playerRoomMaping.put(pid, room.getId());
		
		return room;
	}

	/**
	 * 更换聊天室
	 */
	public ChatRoom changeChatRoom(int chatRoomId,int pid){
		ChatRoom chatRoom = getChatRoom(pid,0);
		int exitChatRoomId = 0;
		if (chatRoom != null) {
			exitChatRoomId = exitChatRoom(pid);
		}
		// 进入指定聊天室
		return enterChatRoom(pid,exitChatRoomId,chatRoomId);
	}
	
	/**
	 * 退出聊天室
	 * @param pid
	 * @return	房间号
	 */
	public int exitChatRoom(int pid){
		int roomId = 0;
		if (playerRoomMaping.containsKey(pid)) {
			roomId = playerRoomMaping.remove(pid);
			ChatRoom chatRoom = chatRoomCache.get(roomId);
			chatRoom.remove(pid);
		}
		return roomId;
	}
}
